/***************************************************************************************************
*Copyright(C),2010-2016,Sumscope
*FileName	:  date.cpp
*Author	:  scofined.qi
*Version	:  1.0
*Date		:  2015/12/18
*Desc		:  //用于主要说明此程序文件完成的主要功能
*Relation :  
*Others	:  //其他内容说明
*Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
*History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#include "date.h"
#include "../Utility.h"

#if defined(WIN32) || defined(_WINDOWS) 
#include <windows.h>

#define localtime_r(ti , tm) localtime_s(tm , ti)
#define gmtime_r(ti , tm) gmtime_s(tm , ti)

#else
#include <sys/time.h>
#endif


namespace qb{
	namespace base{
		time_t getTimeFromInt(int date)
		{
			int year, month, day;
			day = date % 100; date = date / 100;
			month = date % 100; date = date / 100;
			year = date;
			tm t;
			memset(&t, 0, sizeof(t));
			t.tm_year = year;
			t.tm_mon = month;
			t.tm_mday = day;
			return ::mktime(&t);
		}

		time_t make_time(int year, int month, int day, int hour, int minute, int second)
		{
			struct tm tm ;
			memset(&tm , 0 , sizeof(tm)) ;

			tm.tm_year = year - 1900 ;
			tm.tm_mon = month - 1 ;
			tm.tm_mday = day ;

			tm.tm_hour = hour ;
			tm.tm_min = minute ;
			tm.tm_sec = second ;	

			return ::mktime(&tm) ;
		}

		time_t calc_date(time_t time , int& year , int& month , int& day , int& wday)
		{
			struct tm tm ;

			::localtime_r(&time , &tm) ;

			year = tm.tm_year + 1900 ;
			month = tm.tm_mon + 1 ;
			day = tm.tm_mday ;
			wday = tm.tm_wday ;
			if(wday == 0)
				wday = 7 ;

			tm.tm_hour = 0 ;
			tm.tm_min = 0 ;
			tm.tm_sec = 0 ;

			return mktime(&tm) ;
		}

		date::date(int year , int month , int day)
		{
			reset() ;
			time_t t = make_time(year , month , day) ;
			time_ = calc_date(t , year_ , month_ , day_ , wday_) ;
			calc_stage_ = 1 ;	
		}

		void date::reset()
		{
			time_ = 0 ;
			year_ = 0 ;
			month_ = 0 ;
			day_ = 0 ;
			wday_ = 0 ;
			calc_stage_ = 0 ;
		}

		time_t date::time()
		{
			return time_ ;
		}

		time_t date::gmttime()
		{
			return (time_ - (date::timezone() * 3600)) ;
		}

		bool date::calc_now()
		{
			time_ = calc_date(::time(NULL) , year_ , month_ , day_ , wday_) ;
			calc_stage_ = 1 ;

			return true ;
		}

		date::date()
		{
			calc_now() ;
		}

		date::date(time_t time)
		{
			reset() ;

			time_ = calc_date(time , year_ , month_ , day_ , wday_) ;
			calc_stage_ = 1 ;	
		}

		date& date::operator=(time_t ts)
		{
			reset() ;
			time_ = calc_date(ts , year_ , month_ , day_ , wday_) ;	
			calc_stage_ = 1 ;

			return (*this) ;
		}

		bool date::operator==(time_t ts)
		{
			date d(ts) ;
			return (*this) == d ;
		}

		bool date::operator!=(time_t ts)
		{
			date d(ts) ;
			return (*this) != d ;	
		}

		bool date::operator==(const date& d)
		{
			return ((year_ == d.year_) && (month_ == d.month_) && (day_ == d.day_)) ;
		}

		bool date::operator!=(const date& d)
		{
			return !((*this) == d) ;
		}

		bool date::operator<(const date& d)
		{
			return (time_ < d.time_) ;
		}

		bool date::operator<=(const date& d)
		{
			return (time_ <= d.time_) ;
		}

		bool date::operator>(const date& d)
		{
			return (time_ > d.time_) ;
		}

		bool date::operator>=(const date& d)
		{
			return (time_ >= d.time_) ;
		}


		BaseString& date::to_string()
		{
			if(calc_stage_ < 2)
			{
				char str[256] = {0} ;
				FMTBUF(str , "%04d%02d%02d" , year_ , month_ , day_) ;
				datestr_ = str ;

				calc_stage_ = 2 ;
			}

			return datestr_ ;
		}

		date& date::today()
		{
			static date date_today ;
			static time_t last_time = date_today.time() ;

			time_t now = ::time(NULL) ;
			//if((now / 86400) > (last_time / 86400))
			if(now - last_time >= 86400)
			{
				date_today.calc_now() ;
				last_time = date_today.time() ;
			}

			return date_today ;
		}


		int date::timezone()
		{
			static int our_timezone = - 1 ;

			if(our_timezone < 0)
			{
				time_t now = ::time(NULL) ;
				struct tm ltm , gtm ;

				localtime_r(&now , &ltm) ;
				gmtime_r(&now , &gtm) ;


				our_timezone = (ltm.tm_hour + 24 - gtm.tm_hour) %24 ;
			}

			return our_timezone ;
		}

		date& date::next_day(int dc)
		{
			time_t t = time_ + (86400 * dc) ;
			time_ = calc_date(t , year_ , month_ , day_ , wday_) ;	

			calc_stage_ = 1 ;
			return (*this) ;
		}

		utime::utime(bool need_calc)
		{
			if(need_calc)
				calc_now() ;
			else
				reset() ;
		}

		void utime::reset()
		{
			hour_ = 0 ;
			minute_ = 0 ;
			second_ = 0 ;
			usec_ = 0 ;

			calc_stage_ = 0 ;
		}

		utime::~utime()
		{
			//
		}

		void utime::calc_now(int64_t micro)
		{
			time_t sec = 0 ;	
			if(micro == 0)
			{
#if defined(WIN32) || defined(_WINDOWS) 
				FILETIME ft ;

				GetSystemTimeAsFileTime(&ft) ;

				/*
				2011-03-08
				参考BOOST的microsec_time_clock.hpp	将FILETIME转化为毫秒

				shift is difference between 1970-Jan-01 & 1601-Jan-01
				in 100-nanosecond intervals 
				*/
				const uint64_t shift = 116444736000000000ULL; // (27111902 << 32) + 3577643008
				uint64_t caster = ft.dwHighDateTime  ;
				caster = (( caster << 32 ) + ft.dwLowDateTime - shift) / 10 ;

				usec_ = (int64_t)(caster % 1000000UL) ;
				sec = (int64_t)(caster  / 1000000) ;
#else
				struct timeval tv ;
				::gettimeofday(&tv , NULL) ;

				sec = tv.tv_sec ;
				usec_ = tv.tv_usec ;
#endif
			}
			else
			{
				sec = (time_t)(micro / 1000000) ;
				usec_ = (int)(micro % 1000000) ;
			}

			if(sec > 864000)
			{
				date d(sec) ;
				sec -= d.time() ;
			}

			hour_ = (int)(sec / 3600) ;
			minute_ = (int)((sec % 3600) / 60) ;
			second_ = (int)(sec % 60) ;		

			calc_stage_ = 1;
		}

		BaseString& utime::to_string()
		{
			if(calc_stage_ < 2)
			{
				char str[256] = { 0 };
				FMTBUF(str,"%02d:%02d:%02d.%06d" , hour_ , minute_ , second_ , usec_) ;
				usecstr_ = str ;		
			}

			return usecstr_ ;
		}

		int64_t utime::now()
		{
			utime ut(true) ;
			return (((ut.hour() * 3600 + ut.minute() * 60 + ut.second())) * 1000000 + ut.usec()) ;
		}

		const utime& utime::operator=(const utime& src)
		{
			hour_ = src.hour_ ;
			minute_ = src.minute_ ;
			second_ = src.second_ ;
			usec_ = src.usec_ ;

			usecstr_ = src.usecstr_ ;
			calc_stage_ = src.calc_stage_ ;

			return (*this) ;	
		}
		namespace{
			class DateConverter{
				enum { CACHE_MAX = 14 };
				typedef unsigned short ushort;
				typedef unsigned char uchar;
				typedef unsigned int uint;
				struct DayTime{
					time_t		m_today;
					time_t		m_today_end;
					uint		m_date;
				};
				DayTime		m_future[CACHE_MAX];	//0为今天,1为明天
				DayTime		m_passed[CACHE_MAX];	// 0为昨天,1为前天
			public:
				DateConverter()
				{
					Init();
				}
				static DateConverter& Get(){
					static DateConverter dc;
					return dc;
				}
				unsigned int TimeToInt(time_t t)
				{
					if (t >= m_future[0].m_today&&t < m_future[0].m_today_end)//绝大多数数据
						return m_future[0].m_date;
					if (t >= m_future[0].m_today && t<m_future[CACHE_MAX - 1].m_today_end)
					{
						for (int i = 1; i < CACHE_MAX; i++)
							if (t >= m_future[i].m_today&&t < m_future[i].m_today_end)
								return m_future[i].m_date;
					}
					if (t >= m_passed[CACHE_MAX - 1].m_today && t < m_passed[0].m_today_end)
					{
						for (int i = 0; i < CACHE_MAX; i++)
							if (t >= m_passed[i].m_today&&t < m_passed[i].m_today_end)
								return m_passed[i].m_date;
					}
					return TimeToIntImpl(t);
				}
			protected:
				// 差性能版本
				//UINT timeToInt(time_t tTime)
				//{
				//	if (tTime <= 0) return 0;
				//	CTime timeTemp(tTime);
				//	return timeTemp.GetYear() * 10000 + timeTemp.GetMonth() * 100 + timeTemp.GetDay();
				//}
				void Init()
				{
					DayTime dtime;
					time_t now;
					time(&now);

					//time_t 这种类型就是用来存储从1970年到现在经过了多少秒

					struct tm nowtm;
					#if WIN32
					int err = _localtime64_s(&nowtm, &now);
					#else
					nowtm = *localtime(&now);
					#endif

					time_t oneday = (time_t)(24 * 3600);
					time_t passed = (time_t)(nowtm.tm_hour * 3600 + nowtm.tm_min * 60 + nowtm.tm_sec);
					time_t daystart = now - passed;
					for (int i = 0; i < CACHE_MAX; i++)
					{
						dtime.m_today = daystart;
						dtime.m_today_end = daystart + oneday;
						dtime.m_date = TimeToIntImpl(dtime.m_today);
						m_future[i] = dtime;
						daystart = daystart + oneday;
					}
					daystart = now - passed - oneday;
					for (int i = 0; i < CACHE_MAX; i++)
					{
						dtime.m_today = daystart;
						dtime.m_today_end = daystart + oneday;
						dtime.m_date = TimeToIntImpl(dtime.m_today);
						m_passed[i] = dtime;
						daystart = daystart - oneday;
					}
				}
				uint32_t TimeToIntImpl(time_t tTime)
				{
					if (tTime <= 0) return 0;
					struct tm ptmTemp;
					#if WIN32
					int err = _localtime64_s(&ptmTemp, &tTime);
					#else
					int err = 0;
					ptmTemp = *localtime(&tTime);
					#endif
					if (err != 0)
						return 0;
					uint32_t date = 19000100 + ptmTemp.tm_mday;
					uint32_t y = ptmTemp.tm_year, m = ptmTemp.tm_mon;
					//10000 = 8192 + 1024 +512  + 256 + 16;
					//10000 = 2^13 + 2^10 + 2^9 + 2^8 + 2^4;
					//100 = 64 + 32 + 4;
					//100 = 2^6+ 2^5+2^2;
					date += (y << 13) + (y << 10) + (y << 9) + (y << 8) + (y << 4);
					date += (m << 6) + (m << 5) + (m << 2);
					return date;
				}
			};
		}
		//////////////////////////////////////////////////////////////////////////
		void IntDate::UpdateCache()
		{

		}
		unsigned int IntDate::timeToInt(time_t time)
		{
			return DateConverter::Get().TimeToInt(time);
		}
		time_t IntDate::IntToTime(unsigned int intTime)
		{
			/***
			时间分量 取值范围
			nYear 1970-3000
			nMonth 1-12
			nDay 1-31
			nHour 0-23
			nMin 0-59
			nSec 0-59
			***/
			if (intTime <= 0) return 0;
			int nY = intTime / 10000;
			int nM = (intTime / 100) % 100;
			int nD = intTime % 100;
			if (nY < 1970 || nY>3000 || nM > 12 || nM <= 0 || nD <= 0 || nD > 31) //2016/01/27,bushion.xin: 防止数据错误造成time_t异常
				return 0;

			struct tm tt;
			memset(&tt, 0, sizeof(tm));
			tt.tm_year = nY - 1900;
			tt.tm_mon = nM - 1;
			tt.tm_mday = nD;
			tt.tm_hour = 0;
			tt.tm_sec = 1;
			time_t t = mktime(&tt);
			//CTime timeTemp(nY, nM, nD, 0, 0, 1);
			return t;
		}
	}//namespace base;
}//namespace qb;

